﻿using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using ibba.src.sl.recursos.MVVM;
using Infragistics.Documents.Excel;

namespace ibba.src.noriskbo.ViewModels.Base
{
    public abstract class ViewModelImportacaoBase<T> : ViewModelBase where T : IImportacaoModelBase
    {

        #region [ public_propertys ]

        /// <summary>
        /// Coleção dos dados carregado da planilha para preenchimento do grid
        /// </summary>
        public ObservableCollection<T> DadosPlanilha { get; set; }

        /// <summary>
        /// Arquivo do excell selecionado
        /// </summary>
        public FileInfo PlanilhaExcel { get; set; }

        private string _excelFileName;
        public string ExcelFileName
        {
            get { return _excelFileName; }
            protected set { base.SetValue("ExcelFileName", ref _excelFileName, value); }
        }

        private int _excelRowsCount;
        public int ExcelRowsCount
        {
            get { return _excelRowsCount; }
            set { base.SetValue("ExcelRowsCount", ref _excelRowsCount, value); }
        }

        /// <summary>
        /// Retorna true se existir dados
        /// </summary>
        public bool HasData
        {
            get { return DadosPlanilha.Count > 0; }
        }

        /// <summary>
        /// Retorna true se existir dados para importar
        /// </summary>
        public bool HasDataForImport
        {
            get { return DadosPlanilha.Count(a=>a.StatusImportacao != Constantes.StatusImportLote.FINALIZADO) > 0; }
        }

        private bool _isImporting;
        public bool IsImporting
        {
            get { return _isImporting; }
            set
            {
                base.SetValue("IsImporting", ref _isImporting, value);
                base.RaisePropertyChanged("NeedProcessCount");
            }
        }

        private bool _isValidating;
        public bool IsValidating
        {
            get { return _isValidating; }
            set
            {
                base.SetValue("IsValidating", ref _isValidating, value);
                base.RaisePropertyChanged("NeedProcessCount");
            }
        }

        /// <summary>
        /// Retorna true se todos os registro já foram validados
        /// </summary>
        public bool IsValidated
        {
            get
            {
                return (DadosPlanilha.Count > 0
                        && DadosPlanilha.Count(a => string.IsNullOrEmpty(a.StatusImportacao) == true
                                                 || a.StatusImportacao == Constantes.StatusImportLote.PROCESSANDO) == 0);
            }
        }

        /// <summary>
        /// Retorna true se todos os dados foram validados e existe erro
        /// </summary>
        public bool HasError
        {
            get
            {
                //return (DadosPlanilha.Count > 0 
                //        && DadosPlanilha.Where(a=> string.IsNullOrEmpty(a.StatusImportacao) == false
                //                                   && a.StatusImportacao == Constantes.StatusImportLote.ERRO).ToList().Count > 0);
                return this.ErrorCount > 0;
            }
        }

        /// <summary>
        /// Retorna true se todos os dados já foram validados sem error para poder importar
        /// </summary>
        public bool CanImport
        {
            get
            {
                return (DadosPlanilha.Count > 0
                        && DadosPlanilha.Count(a => string.IsNullOrEmpty(a.StatusImportacao) == false
                                                 && a.StatusImportacao == Constantes.StatusImportLote.ERRO) == 0);
            }
        }

        /// <summary>
        /// Retorna a quantidade de registros com status de INCLUSÃO
        /// </summary>
        public int InsertCount
        {
            get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.INCLUSAO); }
        }


        /// <summary>
        /// Retorna a quantidade de registros com status de ALTERAÇÃO
        /// </summary>
        public int UpdateCount
        {
            get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.ALTERACAO); }
        }

        /// <summary>
        /// Retorna a quantidade de registros com status de COPIAR
        /// </summary>
        public int CopyCount
        {
            get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.COPIAR); }
        }


        /// <summary>
        /// Retornar a quantidade de registros com status de ERRO
        /// </summary>
        public int ErrorCount
        {
            get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.ERRO); }
        }

        /// <summary>
        /// Retornar a quantidade de registros com status de PROCESSANDO(efetuando a validação e importacao)
        /// </summary>
        public int ProcessingCount
        {
            get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.PROCESSANDO); }
        }

        public int NeedProcessCount
        {
            //get { return DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.PROCESSAR
            //                                   || a.StatusImportacao == Constantes.StatusImportLote.PROCESSANDO); }

            get
            {
                int proc = 0;

                if (this.IsValidating)
                {
                    proc = DadosPlanilha.Count(a => string.IsNullOrEmpty(a.StatusImportacao) == true
                                                 || a.StatusImportacao == Constantes.StatusImportLote.PROCESSANDO);
                }
                else if (this.IsImporting)
                {
                    proc = DadosPlanilha.Count() 
                           - DadosPlanilha.Count(a => a.StatusImportacao == Constantes.StatusImportLote.FINALIZADO);
                }

                return proc;
            }
        }
        #endregion

        #region [ public_methods ]

        private void GetFileExcel()
        {
            OpenFileDialog dialog = new OpenFileDialog()
            {
                Filter = "Excel Worksheets 2003|*.xls",
                FilterIndex = 1
            };

            if (dialog.ShowDialog() == true)
                PlanilhaExcel = dialog.File;
            else
                PlanilhaExcel = null;

        }

        /// <summary>
        /// Retorna os a worksheet do excel para extração dos dados 
        /// </summary>
        /// <param name="pIndexSheet">Indice de base 0 para retornar a pasta do excel</param>
        /// <returns>Worksheet</returns>
        public Worksheet GetWorksheet(int pIndexSheet)
        {
            Worksheet result = null;
            FileStream stream = null;

            try
            {
                if (PlanilhaExcel == null)
                    return null;

                base.StartBusy();

                if (pIndexSheet == 0)
                    ExcelFileName = PlanilhaExcel.Name;

                stream = PlanilhaExcel.OpenRead();
                Workbook excelFile = Workbook.Load(stream);
                stream.Close();

                if (excelFile == null)
                    return null;

                result = excelFile.Worksheets[pIndexSheet];

                if (pIndexSheet == 0)
                {
                    ExcelRowsCount = result.Rows.Count();
                    ExcelFileName += string.Format(" ({0} linhas)", result.Rows.Count().ToString());
                }

            }
            catch (IOException ioex)
            {
                MessageBoxHelper.ShowErro(AppHelper.NomeSistema, "Não foi possível abrir o arquivo\n\nSe o mesmo estiver aberto, feche-o e tente novamente.", ioex.Message.ToString());
            }
            finally
            {
                if (stream != null)
                    stream.Close();

                base.EndBusy();
            }

            return result;
        }

        #endregion

        #region [ Métodos auxiliares ]

        public virtual void NotifyProperties()
        {
            base.RaisePropertyChanged("HasData");
            base.RaisePropertyChanged("IsValidated");
            base.RaisePropertyChanged("HasError");
            base.RaisePropertyChanged("CanImport");
            base.RaisePropertyChanged("InsertCount");
            base.RaisePropertyChanged("UpdateCount");
            base.RaisePropertyChanged("CopyCount");
            base.RaisePropertyChanged("ErrorCount");
            base.RaisePropertyChanged("ProcessingCount");
            base.RaisePropertyChanged("NeedProcessCount");
        }

        public void RemoveAllErrors(bool pSolicitarConfirmacao)
        {
            if (pSolicitarConfirmacao)
                MessageBoxHelper.ShowQuestion("Limpeza de erros"
                                            , "Deseja remover os registros com erros?"
                                            , sl.componentes.CustomDialogEnums.enumCustomDialogIcons.Delete
                                            , new sl.componentes.CustomDialog.DialogClosed((r) =>
                                                {
                                                    if (r == MessageBoxResult.Yes)
                                                        this.RemoveAllErrors();
                                                })
                                            );
            else
                this.RemoveAllErrors();

        }

        private void RemoveAllErrors()
        {
            var erros = this.DadosPlanilha.Where(a => a.StatusImportacao == Constantes.StatusImportLote.ERRO).ToList();

            foreach (var item in erros)
            {
                this.DadosPlanilha.Remove(item);
            }

            this.NotifyProperties();
        }

        private void RemoveItem(T item)
        {
            DadosPlanilha.Remove(item);
            this.NotifyProperties();
        }

        #endregion

        #region [ Metodos abstratos ]

        /// <summary>
        /// Carregar os dados da planilha selecionada
        /// </summary>
        public virtual void ComandoCarregarPlanilha()
        {

            if (DadosPlanilha.Count > 0)
                MessageBoxHelper.ShowQuestion("Carregar Planilha"
                        , "Ao carregar uma planilha, todos os dados na grade serão apagados!\n\n Deseja continuar?"
                        , new sl.componentes.CustomDialog.DialogClosed((r) =>
                        {
                            if (r == MessageBoxResult.Yes)
                            {
                                this.CarregarPlanilha();
                            }
                            else
                                return;
                        }));
            else
                this.CarregarPlanilha();

        }

        private void CarregarPlanilha()
        {
            this.GetFileExcel();

            Worksheet sheet = this.GetWorksheet(0);

            if (sheet != null)
                CarregarDados(sheet);
        }

        /// <summary>
        /// Metodo abstrato para leitura dos dados existentes na planilha
        /// </summary>
        /// <param name="pSheet"></param>
        protected abstract void CarregarDados(Worksheet pSheet);

        public abstract void ComandoValidarDados();

        public abstract void ComandoImportarDados();

        protected abstract void ValidarRetornoDados(T pEntidade);

        #endregion

    }
}
